package com.huawei.codearts.dao;


import com.huawei.codearts.tools.utils.JedisPoolUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.params.SetParams;

import java.util.List;


@Slf4j
@Repository
//@RequiredArgsConstructor
public class RedisDao {

    @Autowired
    private JedisPool jedisPool;

    /** 字符串 */
    public String set(String key, String value) {
        Jedis jedis = jedisPool.getResource();
        String ok = null;
        try(jedis) {
            ok = jedis.set(key, value);
        } catch (Exception e) {
            log.error("set 传递过来的参数：key={}, value={}, 调用redis异常...{}", key, value, e.getMessage());
        } finally {
            if (jedis != null)
                jedis.close();
        }
        return ok;
    }

    public String get(String key) {
        Jedis jedis = jedisPool.getResource();
        String data = null;
        try(jedis) {
            data = jedis.get(key);
        } catch (Exception e) {
            log.error("get 传递过来的参数：key={}, 调用redis异常...{}", key, e.getMessage());
        } finally {
            if (jedis != null)
                jedis.close();
        }
        return data;
    }

    /** 列表 */
    public long lpush(String key, String value) {
        Jedis jedis = jedisPool.getResource();
        long result = 0L;
        try(jedis) {
            result = jedis.lpush(key, value);
        } catch (Exception e) {
            log.error("lpush 传递过来的参数：key={}, value={}, 调用redis异常...{}", key, value, e.getMessage());
        } finally {
            if (jedis != null)
                jedis.close();
        }
        return result;
    }

    public String rpop(String key) {
        Jedis jedis = jedisPool.getResource();
        String result = null;
        try(jedis) {
            result = jedis.rpop(key);
        } catch (Exception e) {
            log.error("rpop 传递过来的参数：key={}, 调用redis异常...{}", key, e.getMessage());
        } finally {
            if (jedis != null)
                jedis.close();
        }
        return result;
    }

    public List<String> brpop(String source, int timeout) {
        Jedis jedis = jedisPool.getResource();
        List<String> result = null;
        try(jedis) {
            result = jedis.brpop(timeout, source);
        } catch (Exception e) {
            log.error("brpop 传递过来的参数：key={}, timeout={}, 调用redis异常...{}", source, timeout, e.getMessage());
        } finally {
            if (jedis != null)
                jedis.close();
        }
        return result;
    }

    public String brpoplpush(String sourceKey, String destinationKey, int timeout) {
        Jedis jedis = jedisPool.getResource();
        String result = null;
        try(jedis) {
            result = jedis.brpoplpush(sourceKey, destinationKey, timeout);
        } catch (Exception e) {
            log.error("brpoplpush 传递过来的参数：sourceKey={}, destinationKey={}, 调用redis异常...{}", sourceKey, destinationKey, e.getMessage());
        } finally {
            if (jedis != null)
                jedis.close();
        }
        return result;
    }

    public List<String> lrange(String key, long start, long end) {
        Jedis jedis = jedisPool.getResource();
        List<String> result = null;
        try(jedis) {
            result = jedis.lrange(key, start, end);
        } catch (Exception e) {
            log.error("lrange 传递过来的参数：key={}, start={}, end={}, 调用redis异常...{}", key, start, end, e.getMessage());
        } finally {
            if (jedis != null)
                jedis.close();
        }
        return result;
    }

    public long llen(String key) {
        Jedis jedis = jedisPool.getResource();
        long result = 0L;
        try(jedis) {
            result = jedis.llen(key);
        } catch (Exception e) {
            log.error("llen 传递过来的参数：key={}, 调用redis异常...{}", key, e.getMessage());
        } finally {
            if (jedis != null)
                jedis.close();
        }
        return result;
    }

    public long lrem(String key, long count, String value) {
        Jedis jedis = jedisPool.getResource();
        long result = 0L;
        try(jedis) {
            result = jedis.lrem(key, count, value);
        } catch (Exception e) {
            log.error("lrem 传递过来的参数：key={}, count={}, value={}, 调用redis异常...{}", key, count, value, e.getMessage());
        } finally {
            if (jedis != null)
                jedis.close();
        }
        return result;
    }

    /** set nx ex */
    public String setIfAbsent(String key, String val, int expiration) {
        Jedis jedis = jedisPool.getResource();
        String ok = null;
        try {
            // 使用SetParams设置参数
            SetParams setParams = new SetParams();
            setParams.ex((long)expiration); // 设置键的过期时间（ex秒 px毫秒）
            setParams.nx();
            // 使用Jedis和SetParams设置值
            ok = jedis.set(key, val, setParams);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (jedis != null)
                jedis.close();
        }

        return ok;
    }

    // 利用lua转移列表数据
    public void listTransferList(String key, String toKey) {
        Jedis jedis = jedisPool.getResource();
//        String luaScript =
//                """
//                        local source = KEYS[1]\s
//                        local destination = KEYS[2]\s
//                        local count = tonumber(ARGV[1])\s
//                        local elements = redis.call('lpop', source, count)\s
//                        for i,v in ipairs(elements) do\s
//                            redis.call('lpush', destination, v)\s
//                        end\s
//                        return elements""";
//        Object result = jedis.eval(luaScript, 2, key, toKey, String.valueOf(1000000));
        String luaScript =
                """
                        local source = KEYS[1]\s
                        local destination = KEYS[2]\s
                        local elements = redis.call('lrange', source, 0, -1)\s
                        for i,v in ipairs(elements) do\s
                            redis.call('lrem', source, 0, v)\s
                            redis.call('lpush', destination, v)\s
                        end\s
                        return elements""";
        Object result = jedis.eval(luaScript, 2, key, toKey);
        System.out.println("Lua script executed, result: " + result);
        jedis.close();
    }

    public void lremTransferList(String element, String key, String toKey) {
        Jedis jedis = jedisPool.getResource();
        String luaScript =
                """
                        local key = KEYS[1]\s
                        local toKey = KEYS[2]\s
                        local element = ARGV[1]\s
                        redis.call('lrem', key, 0, element)\s
                        local result = redis.call('lpush', toKey, element)\s
                        return result""";
        Object result = jedis.eval(luaScript, 2, key, toKey, element);
        System.out.println("lremTransferList executed, result: " + result);
        jedis.close();
    }

    /** 有序集合 */
    public long zadd(String key, Double score, String value) {
        Jedis jedis = jedisPool.getResource();
        long result = 0L;
        try(jedis) {
            result = jedis.zadd(key, score, value);
        } catch (Exception e) {
            log.error("zadd 传递过来的参数：key={}, score={}, value={}, 调用redis异常...{}", key, score, value, e.getMessage());
        } finally {
            if (jedis != null)
                jedis.close();
        }
        return result;
    }

    // 有序集合数据转移到列表并删除有序集合数据
    public long zsetTransferList(String zsetKey, long minScore, long maxScore, String listKey) {
        Jedis jedis = jedisPool.getResource();

//        List<String> a = jedis.zrangeByScore(zsetKey, minScore, maxScore);
//        System.out.println("zrangeTransferLpush executed, result: " + a);

//        String luaScript =
//                """
//                        local zsetKey = KEYS[1]\s
//                        local listKey = KEYS[2]\s
//                        local min_score = tonumber(ARGV[1])\s
//                        local max_score = tonumber(ARGV[2])\s
//                        local elements = redis.call('ZRANGEBYSCORE', zsetKey, min_score, max_score)\s
//                        for i,v in ipairs(elements) do\s
//                            redis.call('lpush', listKey, v)\s
//                        end\s
//                        local count = redis.call('ZREMRANGEBYSCORE', zsetKey, min_score, max_score)\s
//                        return count""";
        String luaScript =
                """
                        local zsetKey = KEYS[1]\s
                        local listKey = KEYS[2]\s
                        local min_score = tonumber(ARGV[1])\s
                        local max_score = tonumber(ARGV[2])\s
                        local elements = redis.call('ZRANGEBYSCORE', zsetKey, min_score, max_score)\s
                        if #elements > 0 then\s
                            redis.call('lpush', listKey, unpack(redis.call('ZRANGEBYSCORE', zsetKey, min_score, max_score)))\s
                            local count = redis.call('ZREMRANGEBYSCORE', zsetKey, min_score, max_score)\s
                            return count\s
                        else\s
                            return 0\s
                        end\s
                        """;
        Object result = jedis.eval(luaScript, 2, zsetKey, listKey, String.valueOf(minScore), String.valueOf(maxScore));
        System.out.println("zsetTransferList executed, result: " + result);
        jedis.close();
        return (long) result;
    }

    public long rateLimiter(String key, int time, int count) {
        Jedis jedis = jedisPool.getResource();
        String luaScript =
                """
                    local key = KEYS[1]\s
                    local time = tonumber(ARGV[1])\s
                    local count = tonumber(ARGV[2])\s
                    local current = redis.call('get', key)\s
                    if current and tonumber(current) > count then\s
                      return tonumber(current)\s
                    end\s
                    current = redis.call('incr', key)\s
                    if tonumber(current) == 1 then\s
                      redis.call('expire', key, time)\s
                    end\s
                    return tonumber(current)\s
                """;
        Object result = jedis.eval(luaScript, 1, key, String.valueOf(time), String.valueOf(count));
        jedis.close();
        return (long) result;
    }

}
